<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue-table-render</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
          crossorigin="anonymous">
    <style>
        [v-cloak] {
            visibility: hidden;
        }
    </style>
</head>
<body>

<div id="app" v-cloak>
    <v-table :data="data" :columns="columns"></v-table>
</div>

<script src="https://unpkg.com/vue"></script>
<script>
    Vue.component('vTable', {
        render(h) {
            let ths = [];
            let trs = [];
            this.currentColumns.forEach((col, index) => {
               if (col.sortable) {
                   ths.push(h('th', [
                       h('span', col.title),
                       h('button', {
                           class: {
                               'btn btn-default': true,
                               active: col._sortType === 'asc',
                           },
                           on: {
                               click: () => {
                                   this.handleSortByAsc(index)
                           }
                           }
                       }, '↑'),
                       h('button', {
                           class: {
                               'btn btn-default': true,
                               active: col._sortType === 'desc'
                           },
                           on: {
                               click: () => {
                                   this.handleSortByDesc(index)
                               }
                           }
                       }, '↓'),
                   ]));
               }  else {
                   ths.push(h('th', col.title));
               }
            });
            this.currentData.forEach((row) => {
                let tds = [];
                this.currentColumns.forEach((cell) => {
                    tds.push(h('td', row[cell.key]));
                });
                trs.push(h('tr', tds));
            });
            return h('table', {attrs: {class: 'table table-hover'}}, [
                h('thead', [
                    h('tr', ths)
                ]),
                h('tbody', trs)
            ])
        },
        props: {
            columns: {
                type: Array,
                default() {
                    return [];
                }
            },
            data: {
                type: Array,
                default() {
                    return [];
                }
            }
        },
        data() {
            return {
                currentColumns: [],
                currentData: []
            }
        },
        methods: {
            makeColumns() {
                this.currentColumns = this.columns.map((col, index) => {
                    col._sortType = 'normal';
                    col._index = index;
                    return col;
                });
            },
            makeData() {
                this.currentData = this.data.map((row, index) => {
                    row._index = index;
                    return row;
                })
            },
            handleSortByAsc(index) {
                let key = this.currentColumns[index].key;
                this.currentColumns.forEach((col) => {
                    col._sortType = 'normal';
                });
                this.currentColumns[index]._sortType = 'asc';

                this.currentData.sort((a, b) => {
                    return (a[key]>b[key])?1:-1;
                });
            },
            handleSortByDesc(index) {
                let key = this.currentColumns[index].key;
                this.currentColumns.forEach((col) => {
                    col._sortType = 'normal';
                });
                this.currentColumns[index]._sortType = 'desc';

                this.currentData.sort((a, b) => {
                    return (a[key]<b[key])?1:-1;
                });
            }
        },
        watch: {
            data() {
                this.makeData();
                let sortedColumn = this.currentColumns.filter((col) => {
                   return col._sortType !== 'normal';
                });

                if (sortedColumn.length > 0) {
                    if (sortedColumn[0]._sortType === 'asc') {
                        this.handleSortByAsc(sortedColumn[0]._index);
                    } else {
                        this.handleSortByDesc(sortedColumn[0]._index);
                    }
                }
            }
        },
        mounted() {
            this.makeColumns();
            this.makeData();
        }
    });

    let app = new Vue({
        el: '#app',
        data: {
            columns: [
                {
                    title: '姓名',
                    key: 'name'
                },{
                    title: '年龄',
                    key: 'age',
                    sortable: true
                },{
                    title: '出生日期',
                    key: 'birth',
                    sortable: true
                },{
                    title: '地址',
                    key: 'address'
                },
            ],
            data: [
                {
                    name: '王小明',
                    age: 18,
                    birth: '1999-02-21',
                    address: '北京市朝阳区芍药居'
                },{
                    name: '张小刚',
                    age: 25,
                    birth: '1992-01-23',
                    address: '北京市海淀区西二旗'
                },{
                    name: '李小红',
                    age: 30,
                    birth: '1987-11-10',
                    address: '上海市浦东新区世纪大道'
                },{
                    name: '周小伟',
                    age: 26,
                    birth: '1991-10-10',
                    address: '深圳市南山区深南大道'
                },
            ]
        }
    })

</script>
</body>
</html>